import { _decorator, AudioSource, Component, EventTouch, instantiate, Label, Node, Prefab, Sprite, SpriteFrame, tween, Vec2 } from 'cc';
import { Tile } from './Tile';
import { GRID_SIZE } from './Consts';
import { EndPanelController } from './EndPanelController';
const { ccclass, property } = _decorator;

// 最高分
@ccclass('Controller')
export class Controller extends Component {

    // 背景格子, 格子的父节点
    @property(Node)
    grid: Node = null;

    // 格子预制体
    @property(Prefab)
    tilePrefab: Prefab = null;

    // 触摸面板,用于监听滑动
    @property(Node)
    touchPanel: Node = null;

    // 分数
    @property(Label)
    scoreLabel: Label = null;
    // 最高分
    @property(Label)
    bestLabel: Label = null;

    // 结束面板
    @property(Prefab)
    endPanel: Prefab = null;

    // 父节点, 用于添加结束面板
    @property(Node)
    parentNode: Node = null;

    // 合并音效
    @property(AudioSource)
    mergeMusic: AudioSource = null;

    // 分数
    private score: number = 0;
    // 最高分
    private best: number = 0;
    
    // 格子值
    private tileValue: number[][] = [];
    // 格子节点
    private tiles: Node[][] = [];
    
    // 是否开始触摸
    private touchBegin: boolean = false;

    // 滑动该距离才触发
    private touchDistance: number = 50;

    start() {
        this.reset();
        // this.test();
    }

    // 用于测试
    test(){
        this.onEnd();
    }

    /**
     * 重置游戏
     */
    reset() {
        this.cleanGame();
        this.initData();
        this.initGrid();
        this.initNumber();
        this.initLiestenr();
        this.updateUI();
    }

    /**
     * 初始化监听
     * 防止重复监听, 所以需要先解绑再绑定
     */
    initLiestenr(){
        this.touchPanel.off(Node.EventType.TOUCH_START, this.touchStart, this);
        this.touchPanel.off(Node.EventType.TOUCH_MOVE, this.touchMove, this);
        this.touchPanel.on(Node.EventType.TOUCH_START, this.touchStart, this);
        this.touchPanel.on(Node.EventType.TOUCH_MOVE, this.touchMove, this);
    }

    /**
     * 清理游戏
     */
    cleanGame() {
        this.grid.removeAllChildren();
    }

    /**
     * 初始化数据
     */
    initData() {
        for (let i = 0; i < GRID_SIZE; i++) {
            this.tileValue[i] = [];
            this.tiles[i] = [];
            for (let j = 0; j < GRID_SIZE; j++) {
                this.tileValue[i][j] = 0;
                this.tiles[i][j] = null;
            }
        }
        this.score = 0;
    }

    update(deltaTime: number) {
    }

    /**
     * 初始化背景格子
     */
    initGrid() {
        let grid = this.grid;
        for (let i = 0; i < 4; i++) {
            for (let j = 0; j < 4; j++) {
                this.createTile(0, i, j);
            }
        }
    }

    /**
     * 初始化游戏刚开始时的格子
     */
    initNumber() {
        for (let i = 0; i < 2; i++) {
            this.randomdNumber();
        }
    }

    /**
     * 随机位置生成随机数字
     */
    randomdNumber() {
        // let value = Math.pow(2, Math.floor(Math.random()*8) + 1);
        let value = Math.random() < 0.7 ? 2 : 4;
        let emptyList: Vec2[] = [];
        // 找到所有空格子
        for (let i = 0; i < GRID_SIZE; i++) {
            for (let j = 0; j < GRID_SIZE; j++) {
                if (this.tileValue[i][j] == 0) {
                    emptyList.push(new Vec2(i, j));
                }
            }
        }
        // 随机一个空格子
        let pos = emptyList[Math.floor(Math.random() * emptyList.length)];
        this.createTile(value, pos.x, pos.y);
    }

    /**
     * 创建Tile
     * @param value 值
     * @param x 
     * @param y 
     */
    createTile(value: number, x: number, y: number) {
        let tile = instantiate(this.tilePrefab);
        let tileScript = tile.getComponent(Tile);
        tileScript.initTile(value, x, y);
        this.grid.addChild(tile);
        this.tiles[x][y] = tile;
        this.tileValue[x][y] = value;
    }

    /**
     * 监听滑动事件
     * @param event 
     * @returns 
     */
    touchMove(event: EventTouch){
        // 滑动已经触发过,会将touchBegin设置为false, 防止重复触发
        if(this.touchBegin == false){
            return ;
        }
        let delta = event.getLocation().subtract(event.getStartLocation());
        if(Math.abs(delta.x) > this.touchDistance){
            if(delta.x > 0){
                this.moveRight();
            }else{
                this.moveLeft();
            }
            this.touchBegin = false;
        }else if(Math.abs(delta.y) > this.touchDistance){
            if(delta.y > 0){
                this.moveTop();
            }else{
                this.moveBottom();
            }
            this.touchBegin = false;
        }
        // touchBegin为false, 说明已经触发过滑动, 需要更新UI
        if(this.touchBegin == false){
            this.updateUI();
            if(this.checkEnd()){
                this.onEnd();
            }
            tween(this.node).delay(Tile.moveTime).call(() => {
                this.mergeMusic.play();
            }).start();
        }
    }

    /**
     * 触摸开始
     */
    touchStart(event: EventTouch){
        console.log("touchStart");
        this.touchBegin = true;
    }

    moveLeft() {
        console.log("moveLeft");
        let hasMove: boolean = false;
        for(let j = 0; j < GRID_SIZE; j++){
            // 记录需要移动或者合并的位置
            let lastIndex = 0;
            for(let i = 0; i < GRID_SIZE; i++){
                if(lastIndex < 0 || lastIndex >= GRID_SIZE){
                    debugger
                }
                let value = this.tileValue[i][j];
                // 如果是空格子或者是是同一个位置, 则跳过
                if(value == 0 || i == lastIndex){
                    continue;
                }
                // 如果是空格子, 则直接移动过去
                if(this.tileValue[lastIndex][j] == 0){
                    this.moveTile(i, j, lastIndex, j);
                    hasMove = true;
                }else{
                    // 如果是相同的格子, 则合并
                    if(this.tileValue[lastIndex][j] == value){
                        this.mergeTile(i, j, lastIndex, j);
                        lastIndex++;
                        hasMove = true;
                    }else{
                        // 无法合并, 并且相邻,就无法移动, 需要判定下一个
                        if(lastIndex + 1 == i){
                            lastIndex = i;
                            continue;
                        }
                        // 移动到下一个空格子
                        this.moveTile(i, j, lastIndex + 1, j);
                        lastIndex++;
                        hasMove = true;
                    }
                }
            }
        }
        // 如果有移动, 则生成新的数字
        if(hasMove){
            this.randomdNumber();
        }
    }
    moveRight(){
        console.log("moveRight");
        let hasMove: boolean = false;
        for(let j = 0; j < GRID_SIZE; j++){
            // 记录需要移动或者合并的位置
            let lastIndex = GRID_SIZE - 1;
            for(let i = GRID_SIZE - 1; i >= 0; i--){
                if(lastIndex < 0 || lastIndex >= GRID_SIZE){
                    debugger
                }
                let value = this.tileValue[i][j];
                // 如果是空格子或者是是同一个位置, 则跳过
                if(value == 0 || i == lastIndex){
                    continue;
                }
                // 如果是空格子, 则直接移动过去
                if(this.tileValue[lastIndex][j] == 0){
                    this.moveTile(i, j, lastIndex, j);
                    hasMove = true;
                }else{
                    // 如果是相同的格子, 则合并
                    if(this.tileValue[lastIndex][j] == value){
                        this.mergeTile(i, j, lastIndex, j);
                        lastIndex--;
                        hasMove = true;
                    }else{
                        // 无法合并, 并且相邻,就无法移动, 需要判定下一个
                        if(lastIndex - 1 == i){
                            lastIndex = i;
                            continue;
                        }
                        // 移动到下一个空格子
                        this.moveTile(i, j, lastIndex - 1, j);
                        lastIndex--;
                        hasMove = true;
                    }
                }
            }
        }
        // 如果有移动, 则生成新的数字
        if(hasMove){
            this.randomdNumber();
        }
    }

    moveTop() {
        console.log("moveTop");
        let hasMove: boolean = false;
        for(let i = 0; i < GRID_SIZE; i++){
            // 记录需要移动或者合并的位置
            let lastIndex = GRID_SIZE - 1;
            for(let j = GRID_SIZE - 1; j >= 0; j--){
                let value = this.tileValue[i][j];
                // 如果是空格子或者是是同一个位置, 则跳过
                if(value == 0 || j == lastIndex){
                    continue;
                }
                // 如果是空格子, 则直接移动过去
                if(this.tileValue[i][lastIndex] == 0){
                    this.moveTile(i, j, i, lastIndex);
                    hasMove = true;
                }else{
                    // 如果是相同的格子, 则合并
                    if(this.tileValue[i][lastIndex] == value){
                        this.mergeTile(i, j, i, lastIndex);
                        lastIndex--;
                        hasMove = true;
                    }else{
                        // 无法合并, 并且相邻,就无法移动, 需要判定下一个
                        if(lastIndex - 1 == j){
                            lastIndex = j;
                            continue;
                        }
                        // 移动到下一个空格子
                        this.moveTile(i, j, i, lastIndex - 1);
                        lastIndex--;
                        hasMove = true;
                    }
                }
            }
        }
        // 如果有移动, 则生成新的数字
        if(hasMove){
            this.randomdNumber();
        }
    }

    moveBottom() {
        console.log("moveBottom");
    
        let hasMove: boolean = false;
        for(let i = 0; i < GRID_SIZE; i++){
            // 记录需要移动或者合并的位置
            let lastIndex = 0;
            for(let j = 0; j < GRID_SIZE; j++){
                let value = this.tileValue[i][j];
                // 如果是空格子或者是是同一个位置, 则跳过
                if(value == 0 || j == lastIndex){
                    continue;
                }
                // 如果是空格子, 则直接移动过去
                if(this.tileValue[i][lastIndex] == 0){
                    this.moveTile(i, j, i, lastIndex);
                    hasMove = true;
                }else{
                    // 如果是相同的格子, 则合并
                    if(this.tileValue[i][lastIndex] == value){
                        this.mergeTile(i, j, i, lastIndex);
                        lastIndex++;
                        hasMove = true;
                    }else{
                        // 无法合并, 并且相邻,就无法移动, 需要判定下一个
                        if(lastIndex + 1 == j){
                            lastIndex = j;
                            continue;
                        }
                        // 移动到下一个空格子
                        this.moveTile(i, j, i, lastIndex + 1);
                        lastIndex++;
                        hasMove = true;
                    }
                }
            }
        }
        // 如果有移动, 则生成新的数字
        if(hasMove){
            this.randomdNumber();
        }
    }



    /**
     * 移动到目标位置, 目标位置必须为空
     * @param x 
     * @param y 
     * @param targetX 
     * @param targetY 
     */
    moveTile(x: number, y: number, targetX: number, targetY: number){
        this.tiles[targetX][targetY] = this.tiles[x][y];
        this.tiles[x][y] = null;
        this.tileValue[targetX][targetY] = this.tileValue[x][y];
        this.tileValue[x][y] = 0;
        this.tiles[targetX][targetY].getComponent(Tile).moveTile(targetX, targetY);
    }

    /**
     * 合并格子
     * 先消除旧的两个格子, 然后创建新的格子
     */
    mergeTile(x: number, y: number, targetX: number, targetY: number){
        let value = this.tileValue[x][y];
        this.tiles[targetX][targetY].getComponent(Tile).destroyTile();
        this.tiles[targetX][targetY] = null;
        this.tileValue[targetX][targetY] = 0;
        this.tiles[x][y].getComponent(Tile).moveTile(targetX, targetY);
        this.tiles[x][y].getComponent(Tile).destroyTile();
        this.tileValue[x][y] = 0;
        this.tiles[x][y] = null;
        this.createTile(value * 2, targetX, targetY);
        // 计算分数
       this.addScore(value * 2);
    }

    /**
     * 添加分数
     * @param score 
     */
    addScore(score: number){
        this.score += score;
        if(this.score > this.best){
            this.best = this.score;
        }
    }

    /**
     * 更新UI
     */
    updateUI(){
        this.scoreLabel.string = this.score.toString();
        this.bestLabel.string = this.best.toString();
    }
    
    /**
     * 重新开始
     */
    onRestart(){
        this.reset();
    }
    
    /**
     * 游戏结束时触发
     */
    onEnd(){
        let endPanel = instantiate(this.endPanel);
        this.parentNode.addChild(endPanel);
        endPanel.getComponent(EndPanelController).init(this.score, this.best);
        endPanel.getComponent(EndPanelController).addOnRestartListener(() => {
            this.onRestart();
        });
    }

    /**
     * 检查游戏是否结束
     * @returns 是否结束
     */
    checkEnd(){
        for(let i = 0; i < GRID_SIZE; i++){
            for(let j = 0; j < GRID_SIZE; j++){
                // 如果有空格子, 则游戏未结束
                if(this.tileValue[i][j] == 0){
                    return false;
                }
                // 判断与右边和上边是否有相同的格子, 如果有, 则游戏未结束
                // 这样是可以确保每一个格式都与周围的格子进行比较过. 
                if(i + 1 < GRID_SIZE && this.tileValue[i][j] == this.tileValue[i + 1][j]){
                    return false;
                }
                if(j + 1 < GRID_SIZE && this.tileValue[i][j] == this.tileValue[i][j + 1]){
                    return false;
                }
            }
        }
        return true;
    }



}


